// Copyright 2021 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51
//
// Author: Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
//         Basile Bougenot <bbougenot@student.ethz.ch>

#include "vector_macros.h"

void TEST_CASE1(void) {
  VSET(16, e8, m1);
  VLOAD_8(v2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
  VLOAD_8(v3,    0,    1,    2,    3,    7,   15,   31,   32,    0,    1,    2,    3,    7,   15,   31,   32);
  asm volatile ("vsra.vv v4, v2, v3");
  VCMP_U8(1, v4, 0x80, 0xC0, 0xE0, 0xF0, 0xFF, 0xFF, 0xFF, 0x80, 0x80, 0xC0, 0xE0, 0xF0, 0xFF, 0xFF, 0xFF, 0x80);

  VSET(16, e16, m1);
  VLOAD_16(v2, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000);
  VLOAD_16(v3,      0,      1,      2,      3,      7,     15,     31,     32,      0,      1,      2,      3,      7,     15,     31,     32);
  asm volatile ("vsra.vv v4, v2, v3");
  VCMP_U16(2, v4, 0x8000, 0xC000, 0xE000, 0xF000, 0xFF00, 0xFFFF, 0xFFFF, 0x8000, 0x8000, 0xC000, 0xE000, 0xF000, 0xFF00, 0xFFFF, 0xFFFF, 0x8000);

  VSET(16, e32, m1);
  VLOAD_32(v2, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000);
  VLOAD_32(v3,          0,          1,          2,          3,          7,         15,        31,          32,          0,          1,          2,          3,          7,         15,        31,          32);
  asm volatile ("vsra.vv v4, v2, v3");
  VCMP_U32(3, v4, 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 0xFF000000, 0xFFFF0000, 0xFFFFFFFF, 0x80000000, 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 0xFF000000, 0xFFFF0000, 0xFFFFFFFF, 0x80000000);

  VSET(16, e64, m1);
  VLOAD_64(v2, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000);
  VLOAD_64(v3,                  0,                  1,                  2,                  3,                  7,                 15,                 31,                 32,                  0,                  1,                  2,                  3,                  7,                 15,                 31,                 32);
  asm volatile ("vsra.vv v4, v2, v3");
  VCMP_U64(4, v4, 0x8000000000000000, 0xC000000000000000, 0xE000000000000000, 0xF000000000000000, 0xFF00000000000000, 0xFFFF000000000000, 0xFFFFFFFF00000000, 0xFFFFFFFF80000000, 0x8000000000000000, 0xC000000000000000, 0xE000000000000000, 0xF000000000000000, 0xFF00000000000000, 0xFFFF000000000000, 0xFFFFFFFF00000000, 0xFFFFFFFF80000000);
};

void TEST_CASE2(void) {
  VSET(16, e8, m1);
  VLOAD_8(v2, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
  VLOAD_8(v3,    0,    1,    2,    3,    7,   15,   31,   32,    0,    1,    2,    3,    7,   15,   31,   32);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vv v4, v2, v3, v0.t");
  VCMP_U8(5, v4, 0x00, 0xC0, 0x00, 0xF0, 0x00, 0xFF, 0x00, 0x80, 0x00, 0xC0, 0x00, 0xF0, 0x00, 0xFF, 0x00, 0x80);

  VSET(16, e16, m1);
  VLOAD_16(v2, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000);
  VLOAD_16(v3,      0,      1,      2,      3,      7,     15,     31,     32,      0,      1,      2,      3,      7,     15,     31,     32);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vv v4, v2, v3, v0.t");
  VCMP_U16(6, v4, 0x0000, 0xC000, 0x0000, 0xF000, 0x0000, 0xFFFF, 0x0000, 0x8000, 0x0000, 0xC000, 0x0000, 0xF000, 0x0000, 0xFFFF, 0x0000, 0x8000);

  VSET(16, e32, m1);
  VLOAD_32(v2, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000);
  VLOAD_32(v3,          0,          1,          2,          3,          7,         15,        31,          32,          0,          1,          2,          3,          7,         15,        31,          32);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vv v4, v2, v3, v0.t");
  VCMP_U32(7, v4, 0x00000000, 0xC0000000, 0x00000000, 0xF0000000, 0x00000000, 0xFFFF0000, 0x00000000, 0x80000000, 0x00000000, 0xC0000000, 0x00000000, 0xF0000000, 0x00000000, 0xFFFF0000, 0x00000000, 0x80000000);

  VSET(16, e64, m1);
  VLOAD_64(v2, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 0x8000000000000000);
  VLOAD_64(v3,                  0,                  1,                  2,                  3,                  7,                 15,                 31,                 32,                  0,                  1,                  2,                  3,                  7,                 15,                 31,                 32);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vv v4, v2, v3, v0.t");
  VCMP_U64(8, v4, 0x0000000000000000, 0xC000000000000000, 0x0000000000000000, 0xF000000000000000, 0x0000000000000000, 0xFFFF000000000000, 0x0000000000000000, 0xFFFFFFFF80000000, 0x0000000000000000, 0xC000000000000000, 0x0000000000000000, 0xF000000000000000, 0x0000000000000000, 0xFFFF000000000000, 0x0000000000000000, 0xFFFFFFFF80000000);
};

void TEST_CASE3(void) {
  const uint64_t scalar = 2;

  VSET(16, e8, m1);
  VLOAD_8(v2, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0xE0, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, 0xF8, 0xFC);
  asm volatile ("vsra.vx v4, v2, %[A]" :: [A] "r" (scalar));
  VCMP_U8(9, v4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF);

  VSET(16, e16, m1);
  VLOAD_16(v2, 0x0004, 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC);
  asm volatile ("vsra.vx v4, v2, %[A]" :: [A] "r" (scalar));
  VCMP_U16(10, v4, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF);

  VSET(16, e32, m1);
  VLOAD_32(v2, 0x00000004, 0x00000008, 0x0000000C, 0x00000010, 0x00000014, 0x00000018, 0x0000001C, 0x00000020, 0xFFFFFFE0, 0xFFFFFFE4, 0xFFFFFFE8, 0xFFFFFFEC, 0xFFFFFFF0, 0xFFFFFFF4, 0xFFFFFFF8, 0xFFFFFFFC);
  asm volatile ("vsra.vx v4, v2, %[A]" :: [A] "r" (scalar));
  VCMP_U32(11, v4, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 0x00000008, 0xFFFFFFF8, 0xFFFFFFF9, 0xFFFFFFFA, 0xFFFFFFFB, 0xFFFFFFFC, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF);

  VSET(16, e64, m1);
  VLOAD_64(v2, 0x0000000000000004, 0x0000000000000008, 0x000000000000000C, 0x0000000000000010, 0x0000000000000014, 0x0000000000000018, 0x000000000000001C, 0x0000000000000020, 0xFFFFFFFFFFFFFFE0, 0xFFFFFFFFFFFFFFE4, 0xFFFFFFFFFFFFFFE8, 0xFFFFFFFFFFFFFFEC, 0xFFFFFFFFFFFFFFF0, 0xFFFFFFFFFFFFFFF4, 0xFFFFFFFFFFFFFFF8, 0xFFFFFFFFFFFFFFFC);
  asm volatile ("vsra.vx v4, v2, %[A]" :: [A] "r" (scalar));
  VCMP_U64(12, v4, 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, 0x0000000000000005, 0x0000000000000006, 0x0000000000000007, 0x0000000000000008, 0xFFFFFFFFFFFFFFF8, 0xFFFFFFFFFFFFFFF9, 0xFFFFFFFFFFFFFFFA, 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF);
};

void TEST_CASE4(void) {
  const uint64_t scalar = 2;

  VSET(16, e8, m1);
  VLOAD_8(v2, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0xE0, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, 0xF8, 0xFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vx v4, v2, %[A], v0.t" :: [A] "r" (scalar));
  VCMP_U8(13, v4, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0xF9, 0x00, 0xFB, 0x00, 0xFD, 0x00, 0xFF);

  VSET(16, e16, m1);
  VLOAD_16(v2, 0x0004, 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vx v4, v2, %[A], v0.t" :: [A] "r" (scalar));
  VCMP_U16(14, v4, 0x0000, 0x0002, 0x0000, 0x0004, 0x0000, 0x0006, 0x0000, 0x0008, 0x0000, 0xFFF9, 0x0000, 0xFFFB, 0x0000, 0xFFFD, 0x0000, 0xFFFF);

  VSET(16, e32, m1);
  VLOAD_32(v2, 0x00000004, 0x00000008, 0x0000000C, 0x00000010, 0x00000014, 0x00000018, 0x0000001C, 0x00000020, 0xFFFFFFE0, 0xFFFFFFE4, 0xFFFFFFE8, 0xFFFFFFEC, 0xFFFFFFF0, 0xFFFFFFF4, 0xFFFFFFF8, 0xFFFFFFFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vx v4, v2, %[A], v0.t" :: [A] "r" (scalar));
  VCMP_U32(15, v4, 0x00000000, 0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000000, 0x00000008, 0x00000000, 0xFFFFFFF9, 0x00000000, 0xFFFFFFFB, 0x00000000, 0xFFFFFFFD, 0x00000000, 0xFFFFFFFF);

  VSET(16, e64, m1);
  VLOAD_64(v2, 0x0000000000000004, 0x0000000000000008, 0x000000000000000C, 0x0000000000000010, 0x0000000000000014, 0x0000000000000018, 0x000000000000001C, 0x0000000000000020, 0xFFFFFFFFFFFFFFE0, 0xFFFFFFFFFFFFFFE4, 0xFFFFFFFFFFFFFFE8, 0xFFFFFFFFFFFFFFEC, 0xFFFFFFFFFFFFFFF0, 0xFFFFFFFFFFFFFFF4, 0xFFFFFFFFFFFFFFF8, 0xFFFFFFFFFFFFFFFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vx v4, v2, %[A], v0.t" :: [A] "r" (scalar));
  VCMP_U64(16, v4, 0x0000000000000000, 0x0000000000000002, 0x0000000000000000, 0x0000000000000004, 0x0000000000000000, 0x0000000000000006, 0x0000000000000000, 0x0000000000000008, 0x0000000000000000, 0xFFFFFFFFFFFFFFF9, 0x0000000000000000, 0xFFFFFFFFFFFFFFFB, 0x0000000000000000, 0xFFFFFFFFFFFFFFFD, 0x0000000000000000, 0xFFFFFFFFFFFFFFFF);
};

void TEST_CASE5(void) {
  VSET(16, e8, m1);
  VLOAD_8(v2, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0xE0, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, 0xF8, 0xFC);
  asm volatile ("vsra.vi v4, v2, 2");
  VCMP_U8(17, v4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF);

  VSET(16, e16, m1);
  VLOAD_16(v2, 0x0004, 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC);
  asm volatile ("vsra.vi v4, v2, 2");
  VCMP_U16(18, v4, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF);

  VSET(16, e32, m1);
  VLOAD_32(v2, 0x00000004, 0x00000008, 0x0000000C, 0x00000010, 0x00000014, 0x00000018, 0x0000001C, 0x00000020, 0xFFFFFFE0, 0xFFFFFFE4, 0xFFFFFFE8, 0xFFFFFFEC, 0xFFFFFFF0, 0xFFFFFFF4, 0xFFFFFFF8, 0xFFFFFFFC);
  asm volatile ("vsra.vi v4, v2, 2");
  VCMP_U32(19, v4, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 0x00000008, 0xFFFFFFF8, 0xFFFFFFF9, 0xFFFFFFFA, 0xFFFFFFFB, 0xFFFFFFFC, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF);

  VSET(16, e64, m1);
  VLOAD_64(v2, 0x0000000000000004, 0x0000000000000008, 0x000000000000000C, 0x0000000000000010, 0x0000000000000014, 0x0000000000000018, 0x000000000000001C, 0x0000000000000020, 0xFFFFFFFFFFFFFFE0, 0xFFFFFFFFFFFFFFE4, 0xFFFFFFFFFFFFFFE8, 0xFFFFFFFFFFFFFFEC, 0xFFFFFFFFFFFFFFF0, 0xFFFFFFFFFFFFFFF4, 0xFFFFFFFFFFFFFFF8, 0xFFFFFFFFFFFFFFFC);
  asm volatile ("vsra.vi v4, v2, 2");
  VCMP_U64(20, v4, 0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, 0x0000000000000005, 0x0000000000000006, 0x0000000000000007, 0x0000000000000008, 0xFFFFFFFFFFFFFFF8, 0xFFFFFFFFFFFFFFF9, 0xFFFFFFFFFFFFFFFA, 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF);
};

void TEST_CASE6(void) {
  VSET(16, e8, m1);
  VLOAD_8(v2, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, 0x20, 0xE0, 0xE4, 0xE8, 0xEC, 0xF0, 0xF4, 0xF8, 0xFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vi v4, v2, 2, v0.t");
  VCMP_U8(21, v4, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0xF9, 0x00, 0xFB, 0x00, 0xFD, 0x00, 0xFF);

  VSET(16, e16, m1);
  VLOAD_16(v2, 0x0004, 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vi v4, v2, 2, v0.t");
  VCMP_U16(22, v4, 0x0000, 0x0002, 0x0000, 0x0004, 0x0000, 0x0006, 0x0000, 0x0008, 0x0000, 0xFFF9, 0x0000, 0xFFFB, 0x0000, 0xFFFD, 0x0000, 0xFFFF);

  VSET(16, e32, m1);
  VLOAD_32(v2, 0x00000004, 0x00000008, 0x0000000C, 0x00000010, 0x00000014, 0x00000018, 0x0000001C, 0x00000020, 0xFFFFFFE0, 0xFFFFFFE4, 0xFFFFFFE8, 0xFFFFFFEC, 0xFFFFFFF0, 0xFFFFFFF4, 0xFFFFFFF8, 0xFFFFFFFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vi v4, v2, 2, v0.t");
  VCMP_U32(23, v4, 0x00000000, 0x00000002, 0x00000000, 0x00000004, 0x00000000, 0x00000006, 0x00000000, 0x00000008, 0x00000000, 0xFFFFFFF9, 0x00000000, 0xFFFFFFFB, 0x00000000, 0xFFFFFFFD, 0x00000000, 0xFFFFFFFF);

  VSET(16, e64, m1);
  VLOAD_64(v2, 0x0000000000000004, 0x0000000000000008, 0x000000000000000C, 0x0000000000000010, 0x0000000000000014, 0x0000000000000018, 0x000000000000001C, 0x0000000000000020, 0xFFFFFFFFFFFFFFE0, 0xFFFFFFFFFFFFFFE4, 0xFFFFFFFFFFFFFFE8, 0xFFFFFFFFFFFFFFEC, 0xFFFFFFFFFFFFFFF0, 0xFFFFFFFFFFFFFFF4, 0xFFFFFFFFFFFFFFF8, 0xFFFFFFFFFFFFFFFC);
  VLOAD_8(v0, 0xAA, 0xAA);
  VCLEAR(v4);
  asm volatile ("vsra.vi v4, v2, 2, v0.t");
  VCMP_U64(24, v4, 0x0000000000000000, 0x0000000000000002, 0x0000000000000000, 0x0000000000000004, 0x0000000000000000, 0x0000000000000006, 0x0000000000000000, 0x0000000000000008, 0x0000000000000000, 0xFFFFFFFFFFFFFFF9, 0x0000000000000000, 0xFFFFFFFFFFFFFFFB, 0x0000000000000000, 0xFFFFFFFFFFFFFFFD, 0x0000000000000000, 0xFFFFFFFFFFFFFFFF);
};

int main(void){
  INIT_CHECK();
  enable_vec();

  TEST_CASE1();
  TEST_CASE2();
  TEST_CASE3();
  TEST_CASE4();
  TEST_CASE5();
  TEST_CASE6();

  EXIT_CHECK();
}
